'use strict';
/**
 * Axios 对外暴露接口 - 入口方法
 */
var utils = require('./utils');
var bind = require('./helpers/bind');
var Axios = require('./core/Axios');
var mergeConfig = require('./core/mergeConfig');
var defaults = require('./defaults');

/**
 * Create an instance of Axios
 * 创建axios实例
 *
 * @param {Object} defaultConfig The default config for the instance
 * @return {Axios} A new instance of Axios
 */
// 能够实现axios的多种使用方式的核心是createInstance方法
// createInstance最终是希望拿到一个Function，这个Function指向Axios.prototype.request，这个Function还会有Axios.prototype上的每个方法作为静态方法，且这些方法的上下文都是指向同一个对象
function createInstance(defaultConfig) {
  // 创建一个Axios实例
  var context = new Axios(defaultConfig);

  // 更改Axios.prototype.request的this，执行context实例
  // instance等于Axios.prototype.request方法
  // var instance = Axios.prototype.request.bind(context)
  // Axios.prototype.request 内对第一个参数的数据类型判断，使我们能够以 instance(url, option) 方式调用
  var instance = bind(Axios.prototype.request, context);

  // Copy axios.prototype to instance
  // 将Axios.prototype，context上的属性合并到instance，样 instance 就有了 get、post、put等方法
  // instance.get = Axios.prototype.get
  // instance.defaults = context.defaults
  // 等等
  utils.extend(instance, Axios.prototype, context);

  // Copy context to instance
  // 把context对象上的自身属性和方法扩展到instance上
  // 注：因为extend内部使用的forEach方法对对象做for in 遍历时，只遍历对象本身的属性，而不会遍历原型链上的属性
  // 这样，instance 就有了  defaults、interceptors 属性
  utils.extend(instance, context);

  return instance;
}

// axios会直接对使用者暴露一个axios.request的方法，所以我们在使用axios的时候可以这样使用。不需要new一个axios的实例
// import axios from 'axios'
// axios.get('/info')
// Create the default instance to be exported
var axios = createInstance(defaults);

// Expose Axios class to allow class inheritance
axios.Axios = Axios;

// Factory for creating new instances
// axios.create可以根据用户自定义的config生成一个新的axios实例
axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

// Expose Cancel & CancelToken
axios.Cancel = require('./cancel/Cancel');
axios.CancelToken = require('./cancel/CancelToken');
axios.isCancel = require('./cancel/isCancel');

// Expose all/spread
axios.all = function all(promises) {
  return Promise.all(promises);
};
axios.spread = require('./helpers/spread');

module.exports = axios;

// Allow use of default import syntax in TypeScript
module.exports.default = axios;
